package fr.ece.ing4.si.MonteCarlo.Calculation;

import java.util.*;
import java.util.concurrent.ExecutionException;

/**
 * Body of a monte carlo simulator
 * @author matt
 *
 */
public abstract class MonteCarloSimulation
{
	public long SimulationTime=0;
	public double result=0;
	
	/**
	 * Calcul happening on each simulation.
	 * @param CallPutFlag
	 * @param nSteps
	 * @param S
	 * @param X
	 * @param T
	 * @param b
	 * @param v
	 * @return
	 */
	public static double Calcul(String CallPutFlag, int nSteps, double S, double X, double T, double b, double v)
	{
		double dt=0, St=0, Drift=0, vSqrdt=0;
		Random normalInv = new Random();
		int z=0;
		
		if(CallPutFlag.equals("c")) { z = 1; }
		else if(CallPutFlag.equals("p")) { z = -1; }
		
		dt = T / nSteps;
		// System.out.println("dt = " + dt);
		Drift = (b - (int) Math.pow(v, 2) / 2) * dt;
		// System.out.println("Drift = " + Drift);
		vSqrdt = v * Math.sqrt(dt);
		// System.out.println("vSqrdt = " + vSqrdt);
		
		St = S;
		
		for(int i=1; i<nSteps; i++)
		{
			
			St = St * Math.exp(Drift + vSqrdt * normalInv.nextGaussian());
		}
		
		// System.out.println("St: " + St + " ; z: " + z + " ; X: " + X);
		// System.out.println("Return calcul: " + Math.max((z * (St - X)), 0));
		return Math.max((z * (St - X)), 0);
	}
	
	public abstract double Simulation(String CallPutFlag, double S, double X,
		double T, double r, double b, double v, int nSteps, int nSimulations) throws InterruptedException, ExecutionException;
	
	/**
	 * Launcher for the calculation.
	 * @param CallPutFlag
	 * @param S
	 * @param X
	 * @param T
	 * @param r
	 * @param b
	 * @param v
	 * @param nSteps
	 * @param nSimulations
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	public void timeAndComputeValue(String CallPutFlag, double S, double X,
			double T, double r, double b, double v, int nSteps, int nSimulations) throws InterruptedException, ExecutionException
	{
		final long start = System.currentTimeMillis();
		
		this.result = this.Simulation(CallPutFlag, S, X, T, r, b, v, nSteps, nSimulations);
		
		final long end = System.currentTimeMillis();
		
		this.SimulationTime = end - start;
		
		System.out.println("The result of the Monte Carlo Simulation is: " + this.result);
		System.out.println("Time (ms) taken " + this.SimulationTime);
		System.out.println();
	}
	
}

